package com.keqiang.chart.impl.radar.render

import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.Path
import android.text.TextPaint
import com.keqiang.chart.impl.radar.LineStyle
import com.keqiang.chart.impl.radar.XAxis
import com.keqiang.chart.impl.radar.YAxis
import com.keqiang.chart.impl.radar.impl.RadarChart
import com.keqiang.chart.utils.ObjectPool
import com.keqiang.chart.utils.px
import com.keqiang.chart.utils.to360Range
import com.keqiang.chart.utils.toRadian
import com.keqiang.utils.PaintUtils.getCenterBaseline
import com.keqiang.utils.PaintUtils.getChartHeight
import kotlin.math.abs
import kotlin.math.cos
import kotlin.math.sin

/**
 * 雷达图Y轴线绘制器
 *
 * @author Created by wanggaowan on 2022/10/27 13:06
 */
open class YAxisRender(val chart: RadarChart) : IAxisRender {

    override fun onDraw(canvas: Canvas, centerX: Float, centerY: Float, radius: Float, startAngle: Float) {
        val xAxis = chart.xAxis
        val yAxis = chart.yAxis

        val radius2 = radius - xAxis.lineEndPadding
        if (radius2 <= 0) {
            return
        }

        val radiusStep = if (yAxis.labelCount == 1) 0f else radius2 / (yAxis.labelCount - 1)
        if (yAxis.labelCount > 1) {
            var startRadius = radiusStep
            val paint = ObjectPool.obtainPaint<Paint>()
            val path = ObjectPool.obtainPath()

            paint.color = yAxis.lineColor
            paint.strokeWidth = yAxis.lineWidth
            paint.pathEffect = yAxis.linePathEffect
            paint.style = Paint.Style.STROKE

            for (i in 1 until yAxis.labelCount) {
                if (yAxis.lineDrawFactory?.invoke(i) != true) {
                    startRadius += radiusStep
                    continue
                }

                if (yAxis.linePathEffectFactory != null) {
                    paint.pathEffect = yAxis.linePathEffectFactory?.invoke(i)
                }

                path.reset()
                if (yAxis.lineStyle == LineStyle.LINER) {
                    var angle = startAngle
                    val stepAngle = 360f / xAxis.labelCount
                    for (j in 0 until xAxis.labelCount) {
                        val radian = angle.toRadian
                        val x = centerX + cos(radian) * startRadius
                        val y: Float = centerY + sin(radian) * startRadius
                        if (j == 0) {
                            path.moveTo(x, y)
                        } else {
                            path.lineTo(x, y)
                        }
                        angle += stepAngle
                    }
                    path.close()
                } else {
                    path.addCircle(centerX, centerY, startRadius, Path.Direction.CW)
                }

                canvas.drawPath(path, paint)
                startRadius += radiusStep
            }

            ObjectPool.recyclePaint(paint)
            ObjectPool.recyclePath(path)
        }

        if (yAxis.drawLabel) {
            drawLabel(canvas, yAxis, xAxis, startAngle, centerX, centerY, radiusStep)
        }
    }

    protected open fun drawLabel(canvas: Canvas, yAxis: YAxis, xAxis: XAxis, startAngle: Float, cx: Float, cy: Float, radiusStep: Float) {
        val angle = (yAxis.labelDrawStartAngle + startAngle).to360Range
        val radian = angle.toRadian

        // 需要求出半径的一边对应的角
        var angleA = 0f
        // 雷达图构成的三角形过圆心的那一边对应的角
        var angleC = 0f
        if (yAxis.lineStyle == LineStyle.LINER) {
            // 利用正弦定理求出圆心与雷达图三角形边上交点半径距离
            var inAngle = startAngle.to360Range
            val stepAngle = 360f / xAxis.labelCount
            for (j in 0 until xAxis.labelCount) {
                if (inAngle >= angle) {
                    break
                }
                inAngle += stepAngle
            }

            if (inAngle == angle) {
                angleA = 90f
                angleC = 90f
            } else if (inAngle > angle) {
                val angleB = inAngle - angle
                angleA = (180f - stepAngle) / 2f
                angleC = 180f - angleA - angleB
            } else {
                val angleB = angle - inAngle
                angleA = (180f - stepAngle) / 2f
                angleC = 180f - angleA - angleB
            }
        }

        val textPaint = ObjectPool.obtainPaint<TextPaint>(true)
        textPaint.textSize = yAxis.labelTextSize
        textPaint.color = yAxis.labelColor
        textPaint.textAlign = Paint.Align.CENTER
        val oneCharHeight = textPaint.getChartHeight()
        val baseLine = textPaint.getCenterBaseline(includePadding = false)
        val offset = 10f.px
        for (i in 0 until yAxis.labelCount) {
            if (yAxis.lineDrawFactory?.invoke(i) != true) {
                continue
            }

            val label = yAxis.axisValueFormat?.invoke(i)
            if (label.isNullOrEmpty()) {
                continue
            }

            val labelWidth = textPaint.measureText(label)
            var radius = (radiusStep * i + yAxis.labelOffsetAxis)
            val x: Float
            val y: Float
            if (yAxis.lineStyle == LineStyle.CIRCLE) {
                x = cx + cos(radian) * radius
                y = cy + sin(radian) * radius
            } else {
                // 雷达图绘制的是多边形，则需要求与三角形边的交点半径距离
                radius = radius / sin(angleC.toRadian) * sin(angleA.toRadian)
                x = cx + cos(radian) * radius
                y = cy + sin(radian) * radius
            }

            val offsetHeight = if (angle in 0.0..180.0) {
                sin(angle.toRadian) * (oneCharHeight / 2 + offset)
            } else {
                sin(angle.toRadian) * offset
            } + abs(cos(angle.toRadian) * baseLine)

            val offsetWidth = cos(angle.toRadian) * (labelWidth / 2f + offset)
            canvas.drawText(label, x + offsetWidth, y + offsetHeight, textPaint)
        }

        ObjectPool.recyclePaint(textPaint)
    }
}